package com.fingard.dsp.bank.directbank.bocom13.util;

import java.lang.System;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**************************************************************************
 DES/3DES说明:

 1. 8字节密钥, 采用DES

 2. 16字节密钥(分为: 左8字节密钥, 右8字节密钥), 采用3DES.
 加密过程: 左部密钥加密, 右部密钥解密, 左部密钥加密
 解密过程: 左部密钥解密, 右部密钥加密, 左部密钥解密

 3. 24字节密钥(分为: 左8字节密钥, 中8字节密钥, 右8字节密钥), 采用3DES.
 加密过程: 左部密钥加密, 中部密钥解密, 右部密钥加密
 解密过程: 右部密钥解密, 中部密钥加密, 左部密钥解密
 **************************************************************************/

/**
 * 加密算法DES/3DES
 * 
 * @author fanghh
 * @date 2019/4/16
 */
public class Des {
	// 加密算法
	private static final String ALG_DES = "DES/ECB/NoPadding";

	// 加密/解密
	public static byte[] cryptDES(int mode, SecretKeySpec[] key, byte[] data) {
		try {
			Cipher cipher = Cipher.getInstance(ALG_DES);
			if (key.length == 1) {
				cipher.init(mode, key[0]);
				return cipher.doFinal(data);
			} else if (key.length == 2) {
				// 使用左部密钥
				cipher.init(mode, key[0]);
				byte m[] = cipher.doFinal(data);

				// 使用右部密钥
				if (mode == Cipher.DECRYPT_MODE)
					cipher.init(Cipher.ENCRYPT_MODE, key[1]);
				else
					cipher.init(Cipher.DECRYPT_MODE, key[1]);
				byte n[] = cipher.doFinal(m);

				// 使用左部密钥
				cipher.init(mode, key[0]);
				return cipher.doFinal(n);
			} else if (key.length == 3) {
				if (mode == Cipher.DECRYPT_MODE) {
					// 使用右部密钥解密
					cipher.init(mode, key[2]);
					byte a[] = cipher.doFinal(data);

					// 使用中部密钥加密
					cipher.init(Cipher.ENCRYPT_MODE, key[1]);
					byte b[] = cipher.doFinal(a);

					// 使用左部密钥解密
					cipher.init(mode, key[0]);
					return cipher.doFinal(b);
				} else {
					// 使用左部密钥加密
					cipher.init(mode, key[0]);
					byte x[] = cipher.doFinal(data);

					// 使用中部密钥解密
					cipher.init(Cipher.DECRYPT_MODE, key[1]);
					byte y[] = cipher.doFinal(x);

					// 使用右部密钥加密
					cipher.init(mode, key[2]);
					return cipher.doFinal(y);
				}
			} else {
				return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
			}

		} catch (Exception e) {
			// e.printStackTrace();
			return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
		}
	}

	// 加密/解密
	// data 长度必须8的倍数, 不足补充到8位对齐, 补充部分填值0x00
	public static byte[] doDES(int mode, byte[] key, byte[] data) {
		if ((data.length & 0x07) != 0) {
			return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
		}

		try {
			if (key.length == 8) {
				SecretKeySpec[] key8 = { new SecretKeySpec(key, 0, 8, "DES") };
				return cryptDES(mode, key8, data);
			} else if (key.length == 16) {
				SecretKeySpec[] key16 = { new SecretKeySpec(key, 0, 8, "DES"), new SecretKeySpec(key, 8, 8, "DES") };
				return cryptDES(mode, key16, data);
			} else if (key.length == 24) {
				SecretKeySpec[] key24 = { new SecretKeySpec(key, 0, 8, "DES"), new SecretKeySpec(key, 8, 8, "DES"), new SecretKeySpec(key, 16, 8, "DES") };
				return cryptDES(mode, key24, data);
			} else {
				return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
			}
		} catch (Exception e) {
			// e.printStackTrace();
			return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
		}
	}

	/**
	 * 将16进制字符串转换成字节数组
	 * 
	 * @param hexstr
	 * @return
	 */
	public static byte[] hexStr2Bytes(String hexstr) {
		byte b[] = new byte[hexstr.length() >> 1];
		int j = 0;
		for (int i = 0; i < b.length; i++) {
			char c0 = hexstr.charAt(j++);
			char c1 = hexstr.charAt(j++);
			b[i] = (byte) (parse(c0) << 4 | parse(c1));
		}

		return b;
	}

	private static int parse(char c) {
		if (c >= 'a')
			return (c - 97) + 10 & 0x0F;
		if (c >= 'A')
			return (c - 65) + 10 & 0x0F;
		else
			return c - 48 & 0x0F;
	}

	/**
	 * 将字节数组转换成16进制字符串
	 * 
	 * @param b
	 * @return
	 */
	public static String bytes2HexStr(byte b[]) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < b.length; i++)
			sb.append(byteToHexString(b[i]));
		return sb.toString();
	}

	/**
	 * 将字节转换成16进制字符串
	 * 
	 * @param b
	 * @return
	 */
	private static String byteToHexString(byte b) {
		byte hex[] = "0123456789ABCDEF".getBytes();

		byte buff[] = new byte[2];
		buff[0] = hex[b >> 4 & 0x0F];
		buff[1] = hex[b & 0x0F];

		return new String(buff);
	}

	public static void main(String[] args) throws Exception {
		/* 加密前, 明文长度必须为8的倍数, 若不足则补齐, 补齐部分填值为0x00 */
		/* 解密前, 密文长度必须为8的倍数, 否则为密文错误 */

		int i = 0, m = 0, n = 0;

		byte src[] = "test-des1".getBytes();

		n = ((src.length + 0x07) >> 3) << 3;
		byte[] data = new byte[n];
		for (i = 0, m = src.length; i < m; i++)
			data[i] = src[i];
		for (i = m; i < n; i++)
			data[i] = 0x00;

		String stKey24 = "3D7595A98BFF809D70A2718E2D0A042F2963347B392FDE7C";
		String stKey16 = "70A2718E2D0A042F2963347B392FDE7C";
		String stKey08 = "2963347B392FDE7C";

		byte key24[] = hexStr2Bytes(stKey24);
		byte key16[] = hexStr2Bytes(stKey16);
		byte key08[] = hexStr2Bytes(stKey08);

		byte enc24[] = doDES(Cipher.ENCRYPT_MODE, key24, data);
		byte enc16[] = doDES(Cipher.ENCRYPT_MODE, key16, data);
		byte enc08[] = doDES(Cipher.ENCRYPT_MODE, key08, data);

		System.out.println("24-->[" + bytes2HexStr(enc24) + "]");
		System.out.println("16-->[" + bytes2HexStr(enc16) + "]");
		System.out.println("08-->[" + bytes2HexStr(enc08) + "]");

		byte dec24[] = doDES(Cipher.DECRYPT_MODE, key24, enc24);
		byte dec16[] = doDES(Cipher.DECRYPT_MODE, key16, enc16);
		byte dec08[] = doDES(Cipher.DECRYPT_MODE, key08, enc08);

		System.out.println("24-->[" + new String(dec24) + "]");
		System.out.println("16-->[" + new String(dec16) + "]");
		System.out.println("08-->[" + new String(dec08) + "]");
	}
}
